//! Protocol Buffers serialization format example
//!
//! This example demonstrates how to use Protocol Buffers serialization with Kameo.
//! 
//! Run with:
//! ```bash
//! cargo run --example protobuf_serialization --features "remote protobuf"
//! ```

// We need to enable both remote and protobuf features
#[cfg(all(feature = "remote", feature = "protobuf"))]
mod example {
    use kameo::serialization::{self, SerializationConfig, SerializationFormat, ProtobufSerialize, ProtobufDeserialize};
    use prost::Message;
    use serde::{Deserialize, Serialize};
    
    // Define a prost message
    #[derive(Clone, PartialEq, Message)]
    pub struct PersonProto {
        #[prost(string, tag = "1")]
        pub name: String,
        
        #[prost(uint32, tag = "2")]
        pub age: u32,
    }
    
    // Define a serde-compatible struct for comparison
    #[derive(Debug, Serialize, Deserialize)]
    struct Person {
        name: String,
        age: u32,
    }
    
    pub fn run() {
        println!("Protocol Buffers serialization example\n");
        
        // Create data for our examples
        let person = Person {
            name: "Alice".to_string(),
            age: 30,
        };
        
        let person_proto = PersonProto {
            name: "Alice".to_string(),
            age: 30,
        };
        
        // MessagePack for comparison
        let messagepack_bytes = serialization::serialize(&person)
            .expect("Failed to serialize with MessagePack");
        
        println!("MessagePack serialization:");
        println!("- Serialized size: {} bytes", messagepack_bytes.len());
        println!("- Hex: {}", hex_string(&messagepack_bytes));
        
        // Protocol Buffers direct
        let proto_bytes = person_proto.encode_to_vec();
        
        println!("\nProtobuf serialization:");
        println!("- Serialized size: {} bytes", proto_bytes.len());
        println!("- Hex: {}", hex_string(&proto_bytes));
        
        // Deserialize
        let decoded_proto = PersonProto::decode(proto_bytes.as_slice())
            .expect("Failed to decode Protocol Buffers");
        
        println!("- Deserialized fields:");
        println!("  - name: {}", decoded_proto.name);
        println!("  - age: {}", decoded_proto.age);
        
        // Using the Protocol Buffers traits
        let proto_bytes2 = person_proto.to_protobuf()
            .expect("Failed to serialize with Protocol Buffers trait");
        
        println!("\nProtobuf trait serialization:");
        println!("- Serialized size: {} bytes", proto_bytes2.len());
        println!("- Hex: {}", hex_string(&proto_bytes2));
        
        // Deserialize using trait
        let decoded_proto2 = PersonProto::from_protobuf(&proto_bytes2)
            .expect("Failed to deserialize with Protocol Buffers trait");
        
        println!("- Deserialized fields:");
        println!("  - name: {}", decoded_proto2.name);
        println!("  - age: {}", decoded_proto2.age);
        
        // Compare with global serialization using Protocol Buffers
        println!("\nSerializing directly with Protocol Buffers enum:");
        let proto_format = SerializationFormat::Protobuf;
        let result = serialization::serialize_value(&proto_format, &person);
        match result {
            Ok(_) => println!("- Serialized successfully (unexpected!)"),
            Err(e) => println!("- Error (expected): {}", e),
        }
        
        // Size comparison
        println!("\nSize comparison:");
        println!("- MessagePack size: {} bytes", messagepack_bytes.len());
        println!("- Protocol Buffers size: {} bytes", proto_bytes.len());
        println!("- Size ratio: {:.2}x", messagepack_bytes.len() as f64 / proto_bytes.len() as f64);
    }
    
    // Helper function to display binary data as hex
    fn hex_string(bytes: &[u8]) -> String {
        bytes.iter()
            .map(|b| format!("{:02x}", b))
            .collect::<Vec<_>>()
            .join("")
    }
}

// Main entry point
fn main() {
    #[cfg(all(feature = "remote", feature = "protobuf"))]
    example::run();
    
    #[cfg(not(all(feature = "remote", feature = "protobuf")))]
    println!("This example requires both 'remote' and 'protobuf' features. Run with:\ncargo run --example protobuf_serialization --features \"remote protobuf\"");
} 